iT邦幫忙

2023 iThome 鐵人賽

DAY 30
1
Software Development

由淺入深來探討Elasticsearch,從基礎語法到底層相關原理系列 第 30

【Day 30】由淺入深來探討Elasticsearch - 常見問題探討與後記

  • 分享至 

  • xImage
  •  

終於~終於~
我們來到最後一天啦!

在最後一天的內容,我們要來談在開發過程中
可能會遇到的問題與解決方式

Circuit breaker相關錯誤

類型 設定名稱 說明
Parent circuit breaker indices.breaker.total.use_real_memory 確定parent breaker是否應考慮實際記憶體使用情況 (true),還是僅考慮child circuit breakers保留的記憶體量 (false)。 預設為 true。
Parent circuit breaker indices.breaker.total.limit parent breaker的整體記憶體限制。如果indices.breaker.total.use_real_memory設為true,為JVM heap的95%,反之則為70%
Field data circuit breaker indices.breaker.fielddata.limit 將field載入field data cache所需要的記憶體量,設為JVM heap的40%,如果是邏輯複雜的aggregation跟一些expensive query會觸發
  • 當請求觸發circuit breaker時,會返回429 HTTP status code
{
  'error': {
    'type': 'circuit_breaking_exception',
    'reason': '[parent] Data too large, data for [<http_request>] would be [123848638/118.1mb], which is larger than the limit of [123273216/117.5mb], real usage: [120182112/114.6mb], new bytes reserved: [3666526/3.4mb]',
    'bytes_wanted': 123848638,
    'bytes_limit': 123273216,
    'durability': 'TRANSIENT'
  },
  'status': 429
}
  • 在log中也會顯示,方便查找
Caused by: org.elasticsearch.common.breaker.CircuitBreakingException: [parent] Data too large, data for [<transport_request>] would be [num/numGB], which is larger than the limit of [num/numGB], usages [request=0/0b, fielddata=num/numKB, in_flight_requests=num/numGB, accounting=num/numGB]

處理方法

  • 首先可以看有沒有哪個node超出比例
GET _cat/nodes?v=true&h=name,node*,heap*

https://ithelp.ithome.com.tw/upload/images/20231002/20161866QxyiBHT8jD.png

  • 確認可能是哪種circuit breaker超標
GET _nodes/stats/breaker

"breakers": {
        "model_inference": {
          "limit_size_in_bytes": 268435456,
          "limit_size": "256mb",
          "estimated_size_in_bytes": 0,
          "estimated_size": "0b",
          "overhead": 1,
          "tripped": 0 // 不是0的話代表超標
        },
        "inflight_requests": {
          "limit_size_in_bytes": 536870912,
          "limit_size": "512mb",
          "estimated_size_in_bytes": 0,
          "estimated_size": "0b",
          "overhead": 2,
          "tripped": 0
        },
  • 針對不同的壓力來源有不同的處理方法
    • 可以減少shard的數量,一個大shard會比多個小shard佔更少的記憶體
    • 避免expensive searches
      • 減少返回的size數或是減少aggregation buckets能接受的最大數量
      • 直接在cluster settings設置"search.allow_expensive_queries": false來避免expensive searches
    • 避免使用太多層的nested field
    • 使用bulk API時,不要一次匯入太多筆資料
    • 升級node的記憶體大小
    • 如果是Field data circuit breaker,在緊急狀況下可以使用來清除cache
    POST _cache/clear?fielddata=true
    

高CPU壓力

  • 在GET _nodes中我們可以看到各式不同類型的thread_pool
    • 如果thread pool被耗盡,ES會拒絕跟thread pool相關的請求。這也代表可能有些thread執行效率較差
"thread_pool": {
        "force_merge": {
          "type": "fixed",
          "size": 1,
          "queue_size": -1
        },
        "search_coordination": {
          "type": "fixed",
          "size": 2,
          "queue_size": 1000
        },
        "ml_datafeed": {
          "type": "scaling",
          "core": 1,
          "max": 512,
          "keep_alive": "1m",
          "queue_size": -1
        },
......
  • 我們可以透過指令去看CPU的消耗程度
GET _cat/nodes?v=true&s=cpu:desc

紅箭頭為cpu使用率
https://ithelp.ithome.com.tw/upload/images/20231002/20161866psa40gC76l.png

  • 如果今天CPU使用率很高的話,我們可以確認一下哪個node裡面有高消耗的thread
GET _nodes/my-node,my-other-node/hot_threads

處理方法

  • 例如有search處理時間過長,我們可以把task_id找出來並且先手動取消
// 獲取task_id
GET _tasks?actions=*search&detailed

{
  "nodes" : {
    "oTUltX4IQMOUUVeiohTt8A" : {
      "name" : "my-node",
      "transport_address" : "127.0.0.1:9300",
      "host" : "127.0.0.1",
      "ip" : "127.0.0.1:9300",
      "tasks" : {
        "oTUltX4IQMOUUVeiohTt8A:464" : { // 完整task_id
          "node" : "oTUltX4IQMOUUVeiohTt8A",
          "id" : 464,
          "type" : "transport",
          "action" : "indices:data/read/search",
          "description" : "indices[my-index], search_type[QUERY_THEN_FETCH], source[{\"query\":...}]",
          "start_time_in_millis" : 4081771730000,
          "running_time_in_nanos" : 13991383,
          "cancellable" : true
        }
      }
    }
  }
}

// 手動取消任務
POST _tasks/oTUltX4IQMOUUVeiohTt8A:464/_cancel
  • 如果是大量的bulk request或是複雜的search請求,可以把他們分成多步驟分批執行,可以減緩CPU壓力
  • 透過增加node的數量來擴展cluster,增加thread pools更能處理大量的indexing與search處理

Cluster state是黃色或是紅色錯誤排除

  • 通常會出現黃色或紅色的cluster state,可能是因為有shard缺失或是沒有分配到node上
  • 會導致資料遺失風險,或是使cluster表現變差
GET _cluster/health?filter_path=status,*_shards

{
  "status": "green",
  "active_primary_shards": 29,
  "active_shards": 59,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0, //健康的cluster沒有未分配的shard
  "delayed_unassigned_shards": 0
}
  • 可以透過指令去看哪個index的shard出現問題
GET _cat/shards?v=true&h=index,shard,prirep,state,node,unassigned.reason&s=state

https://ithelp.ithome.com.tw/upload/images/20231002/20161866ANQe7gwPBV.png
p 代表是primary shard,r是代表replica shard

處理方法

  • 在index或是cluster層級配置shard allocation的錯誤可能會導致unassigned
    • 可以查看自己的設定是否有任何問題
GET my-index/_settings?flat_settings=true&include_defaults=true

GET _cluster/settings?flat_settings=true&include_defaults=true
  • 注意自己的節點數跟replica數有沒有符合,因為primary跟replica不會在同一個node
  • 使用Cluster reroute API:
POST /_cluster/reroute?metric=none
{
  "commands": [
    {
      "move": {
        "index": "test", "shard": 0,
        "from_node": "node1", "to_node": "node2"
      }
    },
    {
      "allocate_replica": {
        "index": "test", "shard": 1,
        "node": "node3"
      }
    },
		{
      "allocate_empty_primary": {
        "index": "my-index",
        "shard": 0,
        "node": "my-node",
        "accept_data_loss": "true"
      }
    }
  ]
}

在commands中有以下幾種操作

參數名稱 描述
move 將shard從一個node移到另一個node
cancel 可以透過取消現有shard分配,然後重新初始化後讓primary shard同步現有的replica shard
allocate_replica 可以將unassigned的replica shard分配到node上
allocate_stale_primary 會把primary shard分配到replica資料過時的node上,因為資料會進行覆蓋所以使用時需更加注意
allocate_empty_primary 當node上的資料完全無法恢復的話,可以用這個方法,該方法就是把一個空的primary shard移到node上,如果使用該方法的話,即使後面node資料恢復也會被這個空的shard所覆蓋

以上就是最後一天的內容啦
我們探討了不同面向的開發問題與處理方式

  1. JVM heap 超標
    • 減少shard的數量
    • 避免創建太複雜的nested field跟避免使用expensive searches
  2. CPU過載
    • 查看有沒有阻塞的task並且手動取消
    • 增加node來擴展thread pools
  3. cluster健康問題
    • 處理unassigned的shard

希望在開發時遇到類似的問題時,能夠提供解決問題的方向~

以上就是這30天的內容啦!

後記:

感謝任何有看到這裡的人
雖然很膚淺,但是看到有人訂閱或是對文章按like真的對我來說是很大的動力
讓我覺得我有幫助到任何在開發上遇到困難的人

我接觸ES的時間沒有很長,公司會需要用到的業務也不深
加上在開賽前其實大概只寫了3天份就直接開始了
每天這樣閱讀官方文檔,先吸收我能理解的部分,構思成我自己的東西
最後再重新編排文章,有時候可能一天就要花3-4小時才能寫出一篇XD
所以甚至有幾篇是在11:50幾分才能發出XD
原本幾篇文章介紹也會想要用更有趣的方式介紹
然後多做一些流程圖來讓內容更好理解
甚至多放一些我自己操作的內容與response來讓沒接觸過的人更能吸收
但是真的後來連我自己要理解官方文檔在說什麼就耗費我大量的時間跟精力XD
沒有辦法真的完成心中的目標應該是唯一的遺憾吧~

但是另一方面也很為自己感到驕傲
以前這些東西很多時候就是能debug或是處理掉問題就好
背後的原理或是要如何優化整個index或是cluster等等
我先前是沒有這麼多的認知以及理解
這次寫文章時,為了不要誤人子弟,所以在寫的時候我自己也會不斷的去檢查我自己寫的內容有沒有錯誤
遇到自己觀念也不清楚的地方,也會讓自己多去看其他文檔來補齊自己的觀念
在這30天中,我不只是把我會的東西整理出來變成文章
而是也隨著比賽過程讓我學習到更多ES的知識
但是同時也讓我認識到真的還有很多很多ES的相關內容是可以學習的
更別說有關kibana的observability了

這邊也說明一下我整個文章系列的參考對象
在初階的部分是參考udmey上面ES的相關課程
而深入探討的部分則是上完喬叔的進階課程才有更多想法
最後在寫的時候就看官方文檔來完整整個主題的內容

希望這系列的文章有幫助到螢幕前的你或妳~
對於一個去年10月轉職成軟體工程師的我來說
算是轉換跑道後除了自己的side project之外最令我自己滿意的成績單了~
如果後續有關於kibana的內容也會更新上來啦~希望不要挖坑然後不填坑XD

參考資料
circuit breaker errors:
https://www.elastic.co/guide/en/elasticsearch/reference/current/circuit-breaker-errors.html
cluster state error:
https://www.elastic.co/guide/en/elasticsearch/reference/current/red-yellow-cluster-status.html
cpu error:
https://www.elastic.co/guide/en/elasticsearch/reference/current/high-cpu-usage.html


上一篇
【Day 29】由淺入深來探討Elasticsearch - Index lifecycle management API操作
系列文
由淺入深來探討Elasticsearch,從基礎語法到底層相關原理30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言